package com.jetinno.syrup2

import android.os.SystemClock
import com.jetinno.bean.MachineRespond
import com.jetinno.utils.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import java.util.concurrent.locks.ReentrantLock
import kotlin.coroutines.CoroutineContext

/**
 * 糖浆模块
 * Created by Chen on 2020/6/5.
 */
class SyrupProtocol private constructor() : CoroutineScope {
    private val TAG = "SirupProtocol"

    protected var mJob: Job = Job()

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + mJob

    var mSirupCOM: SyrupCOM

    private val HEAD = "E3"//指令头

    private val FUNC_QUERY = "01"//查询
    private val FUNC_EXECUTE = "02"//动作
    private val FUNC_CLEAR = "03"//清除

    init {
        mSirupCOM = SyrupCOM.getInstance()
    }

    companion object {
        val instance: SyrupProtocol by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            SyrupProtocol()
        }
    }

    /**
     * 状态查询
     * send:E30100000900EB
     * receive:E3010000100000007F060100008A
     */
    fun queryStatus(): MachineRespond {
        var cmd = HEAD + FUNC_QUERY + "00000900"
        return sendRecv(cmd)
    }

    ///出杯套
    fun actionCupsleeve(): MachineRespond {
        var cmd = HEAD + FUNC_EXECUTE + "01" + "00"
        return sendRecv(cmd)
    }

    /**
     * 升级底层程序
     * */
    fun upgradeFirmware(cmd: String): Triple<String, String, Boolean> {
        return sendUpgradeRecv(cmd)
    }

    fun upgradeFirmware1(cmd: String): Triple<String, String, Boolean> {
        return sendUpgradeRecv1(cmd)
    }

    /**
     * 糖浆泵动作
     *
     * @param map key:电机号  value:电机动作时间，单位0.1s
     * @param direction 电机转动方向   0x01:正向  0x02:反向
     */
    fun executeSugar(list: MutableList<SyrupMotor>, direction: Int): MachineRespond {
        var cmd = HEAD + FUNC_EXECUTE + "00"
        cmd += convertIntToHex(list.size, 2)
        cmd += convertIntToHex(direction, 2)
        var postion = 0
        for (syrupMotor in list) {
            cmd += convertIntToHex(syrupMotor.motor, 2)
            var time = 0.0
            if (syrupMotor.time > 6553.5) time = 6553.5 else time = syrupMotor.time
            val timeHex = convertIntToHex((time * 10).toInt(), 4)
            val high = timeHex.substring(0, 2)
            val low = timeHex.substring(2, 4)
            cmd += low
            cmd += high
            cmd += convertIntToHex(syrupMotor.speed, 2)
            postion++
        }
        return sendRecv(cmd)
    }

    ///清除故障
    fun clearError(module: Int): MachineRespond {
        var cmd = HEAD + FUNC_CLEAR + convertIntToHex(module, 2)
        return sendRecv(cmd)
    }

    private val lock = ReentrantLock()

    /**
     * 第一个字段是send命令 第二个字段是receive命令 第三个表示是否发送成功
     */
    fun sendRecv(cmd: String): MachineRespond {
        val respond = MachineRespond()
        lock.lock()
        var send = ""
        var data = ""
        var succ = false
        //添加校验码
        val checkXor = checkXor(cmd)
        if (checkXor.isNotBlank()) {
            send = (cmd + checkXor).toUpperCase()
            try {
                if (false) {
                    succ = false
                } else {
                    succ = mSirupCOM.write(send)
                }
//                LogUtils.e(TAG,"send: $send")
//                LogUtils.e(TAG,"写入成功"+succ)

                SystemClock.sleep(200)
//                LogUtils.e(TAG,"读取成功1")
                lock.unlock()
                val receive = mSirupCOM.receive()
                if (succ && receive != null) data = receive
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
//         LogUtils.e(TAG,"读取成功")

//         LogUtils.e(TAG,"data= $data")
        respond.sendCmd = send
        respond.hexResult = data
        return respond
//        return Triple<String, String, Boolean>(send, data, succ && data.isNotBlank())
    }

    fun sendUpgradeRecv(cmd: String): Triple<String, String, Boolean> {
        lock.lock()
        var send = ""
        var data = ""
        var succ = false

        send = cmd.toUpperCase()
        try {
            succ = mSirupCOM.write(send)
            LogUtils.e(TAG, "send: $send")
            SystemClock.sleep(200)
            if (succ) data = mSirupCOM.receive()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        LogUtils.e(TAG, "data= $data")
        lock.unlock()

        return Triple<String, String, Boolean>(send, data, succ && data.isNotBlank())
    }

    fun sendUpgradeRecv1(cmd: String): Triple<String, String, Boolean> {
        lock.lock()
        var send = ""
        var data = ""
        var succ = false

        send = cmd.toUpperCase()
        try {
            succ = mSirupCOM.write(send)
            LogUtils.e(TAG, "send: $send")

            SystemClock.sleep(200)
            if (succ) data = mSirupCOM.receive()
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtils.e(TAG, "异常")
        }

        LogUtils.e(TAG, "data= $data")
        lock.unlock()

        return Triple<String, String, Boolean>(send, data, succ && data.isNotBlank())
    }

    /**
     * 异或校验
     */
    fun checkXor(data: String): String {
//        LogUtils.e(TAG,"checkXor $data")
        if (data.isBlank()) return ""
        var checkData = 0
        for (i in 0..data.length - 1 step 2) {
            //将十六进制字符串转成十进制
            val start = Integer.parseInt(data.substring(i, i + 2), 16)
            //进行异或运算
            checkData = start xor checkData
        }
        return integerToHexString(checkData)
    }

    fun integerToHexString(s: Int): String {
        var ss = Integer.toHexString(s)
        if (ss.length % 2 != 0) {
            ss = "0" + ss
        }
        return ss.toUpperCase()
    }


    fun convertIntToHex(value: Int, length: Int): String {
        var hex = value.toString(16)
        if (hex.length < length) {
            for (index in 1..length - hex.length) {
                hex = "0" + hex
            }
        }
        return hex
    }

    fun reads(): String {
        try {
            SystemClock.sleep(200)
            if (mSirupCOM == null || mSirupCOM.receive() == null) {
                return ""
            }
            return mSirupCOM.receive()
        } catch (e: Exception) {
            LogUtils.d(TAG, e.message)
        }
        return ""

    }

}